/*
 * @Author: Jiraiya
 * @Date: 2020-05-29 14:01:12
 * @LastEditors: Jiraiya
 * @LastEditTime: 2020-06-10 17:02:58
 * @Description: 
 */

/**
 * @param {call} 
 */
Function.prototype.myCall = function (context) {
    context = context || window;
    context.fn = this;
    var args = [];
    for (var i = 1; i < arguments.length; i++) {
        args.push(arguments[i]);
    }
    var res = eval('context.fn(' + args + ')'); //数组字符串化
    delete context.fn;
    return res;
}

Function.prototype.myCallES6 = function (context, ...args) {
    context = context || window;
    context.fn = this;
    const res = context.fn(...args);
    delete context.fn;
    return res;
}







/**
 * @param {apply} 
 */
Function.prototype.myApply = function (context, args) {
    context = context || window;
    context.fn = this;
    var res = eval('context.fn(' + args + ')');
    delete context.fn;
    return res;
}

Function.prototype.myApplyES6 = function (context, args) {
    context = context || window;
    context.fn = this;
    const res = context.fn(...args);
    delete context.fn;
    return res;
}






/**
 * @param {bind} 
 */
Function.prototype.myBindES6 = function(context, ...args){
    const fn = this; 
    if(!context) context = window;
    const fbound = function(...otherArgs){//解决返回的绑定函数当构造函数用,this问题
        return fn.apply(this instanceof fn ? this : context, [...args, ...otherArgs]);
    }
    fbound.prototype = Object.create(fn.prototype);//原型继承
    return fbound;
}








/**
 * @param {new} 
 */
function myNew(Fn, ...args) {
    const context = Object.create(Fn.prototype);
    const res = Fn.apply(context, args);
    if ((typeof res === 'object' && res !== null) || typeof res === 'function'){
        return res;//返回的是对象则返回该对象否则返回this
    }
    return context;
}







/**
 * @param {instanceof} 
 */
function _instanceof(left, right){
    if(typeof left !== 'object' || left === null) return false;
    let proto = Object.getPrototypeOf(left);
    for(;;){
        if(proto === null) return false;
        if(proto === right.prototype) return true;
        proto = Object.getPrototypeOf(proto);
    }
}







/**
 * @param {async/await} 
 */
function asyncGenerator(generatorFn) {
    return function () {
        const gen = generatorFn.apply(this, arguments);
        return new Promise((resolve, reject) => {
            function step(key, val) {
                let result = null;
                try {
                    result = gen[key](val);
                } catch (err) {
                    return reject(err);
                }

                const {
                    done,
                    value
                } = result;
                if (done) {
                    return resolve(value);
                } else {
                    return Promise.resolve(value).then(val => {
                        step('next', val);
                    }).catch(err => {
                        step('throw', err);
                    })
                }
            }
            step('next');
        })
    }
}

function sleep(ms){
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            return resolve(ms);
        }, ms);
    })
}

function *f(ms){
    let s1 = yield sleep(ms);
    console.log('做一些事情：' + s1);
    let s2 = yield sleep(2000);
    console.log('做另外一些事情：' + s2);
    let s3 = yield sleep(3000);
    console.log('做其他一些事情：' + s3);
    return 'finish';
}
const run = asyncGenerator(f);

run(1000).then(res=>{
    console.log(res)
})







/**
 * @param {Object.is} 
 */
function objectIs(x, y) {
    if (x === y) {
        return x !== 0 || y !== 0 || 1 / x === 1 / y;
    }
    return x !== x && y !== y;
}







/**
 * @param {Object.assign} 
 */
function objectAssign(origin, ...args) {
    args.forEach(obj => {
        if(typeof obj === 'object' && obj !== null){
            for(let key in obj){
                if(obj.hasOwnProperty(key)){
                    origin[key] = obj[key];
                }
            }
        };
    })
    return origin;
}


function F(){
    this.a=1;
    return /\d/
}
const a = new F();
console.log(a)